package com.woniuxy.gateway.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.woniuxy.gateway.config.AuthenticationUrlProperties;
import com.woniuxy.gateway.util.JWTUtil;
import com.woniuxy.gateway.util.Result;
import com.woniuxy.core.exception.PawnException;
import com.woniuxy.redis.util.RedisUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;

/**
 * 登录认证器
 */
@Component
@Order(1)
public class  AuthenticationFilter implements GlobalFilter {
    @Resource
    private AuthenticationUrlProperties urls;

    private AntPathMatcher pm = new AntPathMatcher();

    @Resource
    private RedisUtil redisUtil;

    /**
     * 是否公共资源
     * @param url
     * @return
     */
    private boolean isBaseUrl(String url){
        if (ObjectUtil.isNotEmpty(url)){
            for (String baseUrl : urls.getBaseUrls()) {
                if (pm.match(baseUrl,url)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否系统放行资源
     * @param url
     * @return
     */
    private boolean isAdminUrl(String url){
        if (ObjectUtil.isNotEmpty(url)){
            for (String baseUrl : urls.getAdminUrls()) {
                if (pm.match(baseUrl,url)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否用户放行资源
     * @param url
     * @return
     */
    private boolean isUserUrl(String url){
        if (ObjectUtil.isNotEmpty(url)){
            for (String baseUrl : urls.getUserUrls()) {
                if (pm.match(baseUrl,url)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 统一响应
     * @param exchange
     * @return
     */
    private Mono<Void> response(ServerWebExchange exchange){
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        Result result = Result.fail(401, "未登录");
        String json = JSONUtil.parse(result).toString();
        return exchange.getResponse().writeWith(Mono.fromSupplier(()->{
            return exchange.getResponse().bufferFactory().wrap(json.getBytes());
        }));
    }

    /**
     * 登录认证过滤
     * @param exchange
     * @param chain
     * @return
     * @throws PawnException
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) throws PawnException {
        String url = exchange.getRequest().getPath().toString();
        //判断是否普通资源
        if (isBaseUrl(url)){
            return chain.filter(exchange);
        }
        //判断访问资源是什么类别 管理、用户
        else{
            List<String> headers = exchange.getRequest().getHeaders().get("token");
            String token = null;
            if (!ObjectUtils.isEmpty(headers)) token = headers.get(0);
            if (url.endsWith(".user")){
                //管理资源
                if (isUserUrl(url)) return chain.filter(exchange);
                else {
                    //解析管理员token
                    if (token==null){
                        throw new PawnException(401,"未登录");
                    }else {
                        String refreshToken = redisUtil.get(token);
                        if (refreshToken==null) throw new PawnException(401,"未登录");
                        try {
                            JWTUtil.parseUserToken(refreshToken);
                            return chain.filter(exchange);
                        } catch (Exception e) {
                            throw new PawnException(401,"未登录");
                        }
                    }
                }
            }else{
                if (isAdminUrl(url)) {
                    return chain.filter(exchange);
                }
                else {
                    if (token==null) {
                        throw new PawnException(401,"未登录");
                    }
                    else {
                        String refreshToken = redisUtil.get(token);
                        if (refreshToken==null) throw new PawnException(401,"未登录");
                        try {
                            JWTUtil.parseAdminToken(refreshToken);
                            return chain.filter(exchange);
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new PawnException(401,"未登录");
                        }
                    }
                }
            }
        }
    }
}
